﻿(function(){
	var isMoblie;
	function inMoblie(){
		var sUserAgent = navigator.userAgent.toLowerCase(),
			browsers = ["ipad","iphone os","midp","rv:1.2.3.4","ucweb","android","windows ce","windows mobile"];
			
		$.each(browsers,function(i,browser){
			if(sUserAgent.indexOf(browser) > -1)
			{
				isMoblie = true;
				return false;
			}
		})
		return isMoblie;
	}
	inMoblie();
	//事件兼容
	var dragEvent = {
		onstart : (isMoblie ? "touchstart" : "mousedown") + ".drag",
		onmove : (isMoblie ? "touchmove" : "mousemove") + ".drag",
		onend : (isMoblie ? "touchend" : "mouseup") + ".drag"
	}
	//获取mouse或touch事件正确的位置
	function fixEvent(e){
		if(isMoblie)
		{
			var touch = e.originalEvent.touches[0];
			e.pageX = touch.pageX;
			e.pageY = touch.pageY;
		}
		return e
	}
	
	$.fn.drag = function(op){
		op = $.extend({
			handler:null,
			panel:null,
			css:null,
			fixed:null,
			offset:null,
			clickable:null,
			virtual:true,
			lock:true,
			fnFiexdPosition:null,
			onDragStart:null,
			onMoving:null,
			onDroped:null
		},op);
		
		var mover,fixed,virtual,fnDelay,
		dragger = {
			start:function(e){
				e.stopPropagation();
				var trigger = this,
					doc = $(document).one(dragEvent.onend,dragger.drop);

				$.browser.msie && doc.one('selectstart',function(){return false;})

				if(op.clickable)
				{
					fnDelay = setTimeout(function(){
						$.browser.msie || winLock.show();
						dragger.dragStart.call(trigger,e);
						fnDelay = null;
					},200);
				}
				else
					dragger.dragStart.call(trigger,e);
			},
			dragStart:function(e){
				$('div .ccay-selector:visible').hide();
				var trigger = $(this),handler = op.handler ? $(op.handler) : trigger,pos;
				//判断是否使用虚拟对象
				if(checkVirtual(op,trigger)){
					virtual = true;
					pos = op.offset ? handler.offset() : handler.position();
					mover = getMover(handler,op.css);
					mover.data("trigger",handler);
				}
				else
				{
					virtual = null;
					pos = op.offset ? trigger.offset() : trigger.position();
					mover = handler.addClass("ccay-mover").data("trigger",trigger);
				}
				//设置鼠标捕获
				if(mover[0].setCapture){
                	mover[0].setCapture();
            	}
            	else
            	{
            		e.preventDefault(); 
            	}
            	
				op.fnFiexdPosition && (pos = op.fnFiexdPosition(trigger,pos,mover,op,e));
				//mover.css(pos).show();
				fixEvent(e);

				if(!op.onDragStart || op.onDragStart.call(this,e,pos,mover,trigger || mover,op) !== false)
				{
					$(document).on(dragEvent.onmove,dragger.moving);
					mover.css(pos).show();
					fixed = {y : pos.top - e.pageY,x : pos.left - e.pageX};
					if(op.fixed)
					{
						pos.top += (op.fixed.y || 0);
						pos.left += (op.fixed.x || 0);
						fixed.y += (op.fixed.y || 0);
						fixed.x += (op.fixed.x || 0);
					}
				}
				
			},
			moving:function(e){
				e.preventDefault();
				//log(["move",e.originalEvent.pageX,e.originalEvent.pageY]);
				if(!$.browser.msie || $.browser.version > 8 || e.button){
					fixEvent(e);
					var pos = {top : e.pageY + fixed.y,left:e.pageX + fixed.x};
					if(!op.onMoving || op.onMoving(e,pos,mover,mover.data("trigger") || mover,op) !== false)
					{
						mover.css(checkBoundary(mover,pos,op.panel));
					}
				}
				else
					dragger.drop(e);
			},
			drop:function(e){
				if(fnDelay)
				{
					clearTimeout(fnDelay);
					fnDelay = null;
					return;
				}
				e.preventDefault();
				//log(["drop",e.pageX,e.pageY]);
				if(mover){
					//移除鼠标捕获区域
					mover[0].releaseCapture && mover[0].releaseCapture();
	            	
					var trigger,pos = mover.position();
					if(virtual || op.handler)
					{
						trigger = mover.data("trigger");
						mover.removeData("trigger");
					}
					
					if(virtual){
						trigger.css(pos);
						mover.hide().attr('class','ccay-mover ccay-mover-vbox').empty();
					}
					else
						mover.removeClass("ccay-mover");
					
					$(document).off(dragEvent.onmove);
					op.onDroped && op.onDroped(e,pos,mover,trigger || mover,op);
					mover = null;
					fixed = null;
					winLock.hide();
				}
			}
		};

		if(op.target)
		 	this.delegate(op.target,dragEvent.onstart,dragger.start);
		else
		 	this.bind(dragEvent.onstart,dragger.start);
		 	
		 return this;
	}
	
	var getMover = function(trigger,css){
		var mover = $('#drag_mover');
		if(mover.length == 0)
			mover = $.create("div","ccay-mover ccay-mover-vbox","drag_mover").appendTo(document.body);
			
		if(!css)
			css = {width:trigger.outerWidth(),height:trigger.outerHeight()};
			
		return mover.css(css);
	},
	checkVirtual = function(op,trigger){
		if(op.virtual)
		{
			if(typeof(op.virtual) == 'function')
				return op.virtual(trigger,op);
				
			return true;
		}
	},
	winLock = {
		show:function(){
//			var lock = $('#dragger_lock'),win = $(window);
//			if(!lock.length)
//				lock = $.create('div',null,'dragger_lock').attr("tabindex",-1).appendTo(document.body);
//			
//			lock.width(win.width() + win.scrollLeft())
//				.height(win.height() + win.scrollTop()).show().focus();
			$(document.body).addClass('unselect');
		},
		hide:function(){
//			var lock = $('#dragger_lock');
//			lock.length && lock.hide();
			$(document.body).removeClass('unselect');
		}
	},
	checkBoundary = function(target,pos,container,fnHandle){
		var min = {x:0,y:0},max;
		if(container)
		{
			var pos = container.position();
			min.x = pos.left;
			min.y = pos.top;
		}
		else
			container = $(window);

		max = {x:min.x + container.outerWidth() + container.scrollLeft(),
				y:min.y + container.outerHeight() + container.scrollTop()
		}
		if(!pos) pos = target.position();
		var width = target.outerWidth(),height = target.outerHeight(),
			curPos = {
			left : pos.left > min.x ? (pos.left + width > max.x ? max.x - width : pos.left) : min.x,
			top : pos.top > min.y ? (pos.top + height > max.y ? max.y - height : pos.top) : min.y
		}
		curPos.left < 0 && (curPos.left = 0);
		curPos.top < 0 && (curPos.top = 0);
		return fnHandle ? fnHandle(curPos,pos,min,max) : curPos;
	}
})();